package org.atf.mgr;


import java.util.Calendar;
import java.util.HashMap;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;

import org.atf.command.AtfLocal;
import org.atf.command.AtfRemote;
import org.atf.model.dao.PreferenceDAO;
import org.atf.model.dao.ServerDAO;
import org.atf.model.entity.Audit;
import org.atf.model.entity.Preference;
import org.atf.model.entity.Server;
import org.atf.services.TaskStatus;
import org.atf.utils.ATFUtils;
import org.apache.commons.lang3.StringEscapeUtils;

public class WASAppManagerImpl extends AppManager{
	private StringBuffer output = new StringBuffer();
	private StringBuffer error = new StringBuffer();
	private StringBuffer description= new StringBuffer();
	private boolean running;
	private Calendar startTime;
	private Calendar endTime;
	private ProfileManager profileManager= null;
	private int threadNum= 1;
	private Server server= null;
	private ServerDAO serverDAO= new ServerDAO();
	private PreferenceDAO preferenceDAO= new PreferenceDAO();
	ExecutorService executor = Executors.newFixedThreadPool(threadNum);
	FutureTask<String> futureTask  = null;
	private long waitTimeToCheck = 200L;
	private String taskName;
	private AtfRemote atfRemote= new AtfRemote();
	private AtfLocal atfLocal= new AtfLocal();
	
	private String username= "";
		

	@Override
	public ProfileManager getProfileManager() {
		// TODO Auto-generated method stub
		return this.profileManager;
		
	}
	
	@Override
	public void setProfileManager(ProfileManager profileManager) {
		// TODO Auto-generated method stub
		this.profileManager=profileManager;
	}

	

	@Override
	public Calendar getStartTime() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Calendar getStopTime() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Boolean isRunning() {
		// TODO Auto-generated method stub
		if(futureTask != null){
			if(futureTask.isDone()){
				return false;
			}else{
				return true;
			}
		}
		return false;
	}

	@Override
	public String getOutput() {
		// TODO Auto-generated method stub
		if(output.length() > 0){
			return output.toString();
		}else{
			return "";
		}
		
	}

	@Override
	public String getErrors() {
		// TODO Auto-generated method stub
		if(error.length() > 0){
			return error.toString();
		}else{
			return "";
		}
		
	}

	@Override
	public int getStatusCode() {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public void setServer(Server server) {
		// TODO Auto-generated method stub
		this.server= server;
	}

	@Override
	public Server getServer() {
		// TODO Auto-generated method stub
		return this.server;
	}

	@Override
	public void setUsername(String username) {
		// TODO Auto-generated method stub
		this.username=username;
	}

	@Override
	public String getUsername() {
		// TODO Auto-generated method stub
		return username;
	}

	@Override
	public void startServer() {
		// TODO Auto-generated method stub
		if(futureTask == null){
			taskName= "START";
			
			futureTask = new FutureTask<String>(new Callable<String>(){

				public String call() throws Exception {
					// TODO Auto-generated method stub	
					running = true;
					clearDescription();
					description=description.append("Start Server");
					startTime= Calendar.getInstance();
					String result= profileManager.startServer(server);
					endTime= Calendar.getInstance();
					running = false;
					ATFUtils.addAudit(new Audit(getUsername(),server.getId(),taskName,startTime.getTime(),endTime.getTime(),server.getServername()+":"+result));
					server.setStatus(result);
					serverDAO.updateServeStatusById(server.getId(), server.getStatus());
					return result;
					
				}
				
			});
			executor.execute(futureTask);
		}
	}

	@Override
	public void stopServer() {
		// TODO Auto-generated method stub
		
		if(futureTask == null){
			taskName= "STOP";
			
			futureTask = new FutureTask<String>(new Callable<String>(){

				public String call() throws Exception {
					// TODO Auto-generated method stub	
					running = true;
					clearDescription();
					description=description.append("Stop Server");
					startTime= Calendar.getInstance();
					String result= profileManager.stopServer(server);
					endTime= Calendar.getInstance();
					running = false;
					ATFUtils.addAudit(new Audit(getUsername(),server.getId(),taskName,startTime.getTime(),endTime.getTime(),server.getServername()+":"+result));
					server.setStatus(result);
					serverDAO.updateServeStatusById(server.getId(), server.getStatus());
					return result;
					
				}
				
			});
			executor.execute(futureTask);
		}
	}
	@Override
	public void restartServer() {
		// TODO Auto-generated method stub
		if(futureTask == null){
			taskName= "RESTART";
		
			futureTask = new FutureTask<String>(new Callable<String>(){

				public String call() throws Exception {
					// TODO Auto-generated method stub	
					running = true;
					clearDescription();
					description=description.append("Restart Server");
					startTime= Calendar.getInstance();
					String result= profileManager.restartServer(server);
					endTime= Calendar.getInstance();
					running = false;
					ATFUtils.addAudit(new Audit(getUsername(),server.getId(),taskName,startTime.getTime(),endTime.getTime(),server.getServername()+":"+result));
					server.setStatus(result);
					serverDAO.updateServeStatusById(server.getId(), server.getStatus());
					return result;
					
				}
				
			});
			executor.execute(futureTask);
		}
	}

	@Override
	public void serverStatus() {
		// TODO Auto-generated method stub
		if(futureTask == null){
			taskName= "STATUS";
			
			futureTask = new FutureTask<String>(new Callable<String>(){

				public String call() throws Exception {
					// TODO Auto-generated method stub	
					running = true;
					clearDescription();
					description=description.append("Server Status");
					startTime= Calendar.getInstance();
					String status = profileManager.serverStatus(server);
					server.setStatus(status);
					serverDAO.updateServeStatusById(server.getId(), server.getStatus());
					
					endTime= Calendar.getInstance();
					running = false;
					ATFUtils.addAudit(new Audit(getUsername(),server.getId(),taskName,startTime.getTime(),endTime.getTime(),server.getServername()+":"+status));
					return status;
					
				}
				
			});
			executor.execute(futureTask);
		}else{
			error.append("Already a Task Running");
		}

	}
	

	@Override
	public TaskStatus getTaskStatus() {
		// TODO Auto-generated method stub
		
		TaskStatus task= new TaskStatus();
		task.setTaskId(Integer.toString(server.getId()));
		task.setServerId(server.getId());
		task.setServerName(server.getServername());
		task.setUsername(username);
		if(startTime != null){
			task.setStartDate(startTime.getTime());
		}
		
		task.setProfileId(profileManager.getProfileDetails().getId());
		try {
			String s ;
			if(isRunning()){
				task.setStatus("running");
			}else{	
				s= futureTask.get();
				if( s != null){
					task.setStatus("completed");
					output.append(s);
				}
			}
			
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ExecutionException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} 
		if(taskName != null){
			task.setTask(taskName);
		}
		task.setComment(description.toString());
		task.setOutput(getOutput());
		task.setError(getErrors());
		if(endTime != null){
			task.setEndDate(endTime.getTime());
		}
		
		return task;
	}

	@Override
	public void shutdown() {
		// TODO Auto-generated method stub
		this.executor.shutdown();
	}

	@Override
	public void deploy(final HashMap<String, String> options) {
		// TODO Auto-generated method stub
		if(futureTask == null){
			taskName= "DEPLOY";
			
			System.out.println("Adding Deployment task:  "+server.getServername());
			if(!running){
				clearOutput();
				clearError();
				clearDescription();
			}
			
			description=description.append("Deployment Started");
			futureTask = new FutureTask<String>(new Callable<String>(){

				public String call() throws Exception {
					// TODO Auto-generated method stub	
					
					running = true;
					startTime= Calendar.getInstance();
					AtfRemote atfRemote = null;
					AtfLocal atflocal = null;
					boolean sshEnabled  = false ;
					Preference sshEnabledPref=preferenceDAO.getPreferenceByName(profileManager.getProfileDetails().getId(), server.getId(), "SSH_ENABLED", "SERVER");
					Preference deployScript=preferenceDAO.getPreferenceByName(profileManager.getProfileDetails().getId(), server.getId(), "DEPLOY_SCRIPT", "SERVER");
					Preference scriptPath=preferenceDAO.getPreferenceByName(profileManager.getProfileDetails().getId(), server.getId(), "SCRIPT_PATH", "SERVER");
					Preference scriptSudo=preferenceDAO.getPreferenceByName(profileManager.getProfileDetails().getId(), server.getId(), "SCRIPT_SUDO", "SERVER");	
					if(sshEnabledPref != null){
						
						sshEnabled=Boolean.valueOf(sshEnabledPref.getpValue());
						System.out.println("SSH ENABLED : "+sshEnabled);
					}
					String appName=ATFUtils.getApplicationName(server.getServername());
					if(sshEnabled){
						System.out.println("Remote Execution is enabled.. ");
						Preference sshUsername=preferenceDAO.getPreferenceByName(profileManager.getProfileDetails().getId(), server.getId(), "SSH_USERNAME", "SERVER");
						Preference sshPassword=preferenceDAO.getPreferenceByName(profileManager.getProfileDetails().getId(), server.getId(), "SSH_PASSWORD", "SERVER");
						Preference sshKnownHostFile=preferenceDAO.getPreferenceByName(profileManager.getProfileDetails().getId(), server.getId(), "SSH_KNOWN_HOST_FILE", "SERVER");
						Preference sshPort=preferenceDAO.getPreferenceByName(profileManager.getProfileDetails().getId(), server.getId(), "SSH_PORT", "SERVER");		
						Preference deployFromServerScope=preferenceDAO.getPreferenceByName(0, server.getId(), "DEPLOY_FROM_SERVER", "SERVER");
						
						
						atfRemote= new AtfRemote();
						atfRemote.setOutputBuffer(output);
						atfRemote.setErrorBuffer(error);
						
						if(deployFromServerScope != null){
							if(deployFromServerScope.getpValue().equalsIgnoreCase("true")){
								atfRemote.setHostname(server.getHostname());
							}else{
								atfRemote.setHostname(profileManager.getProfileDetails().getHostname());
							}	
						}else{
							atfRemote.setHostname(profileManager.getProfileDetails().getHostname());
						}
						
						if(sshUsername != null){
							atfRemote.setUsername(sshUsername.getpValue());
						}
						if(sshPassword != null){
							atfRemote.setPassword(ATFUtils.decode(sshPassword.getpValue()));
							
						}
						if(sshKnownHostFile != null){
							atfRemote.setKnownHostsFilename(sshKnownHostFile.getpValue());
						}
						if(sshPort != null){
							atfRemote.setPort(Integer.parseInt(sshPort.getpValue()));
						}
						String cmd="";
						if(deployScript != null && !deployScript.getpValue().equalsIgnoreCase("")){
								cmd+=deployScript.getpValue();

						}else if(scriptPath != null && !scriptPath.getpValue().equalsIgnoreCase("")){
								cmd+=scriptPath.getpValue()+"/deploy/Deploy.sh";
								
						}else{
								cmd+="Deploy.sh";
						}
						
						if(scriptSudo != null){
							cmd=scriptSudo.getpValue()+" "+cmd;
						}
						System.out.println("Command to execute: "+cmd);
						atfRemote.setCommand(cmd);
						String arguments=ATFUtils.getDeployParameters(options);	
						
						arguments+=" "+appName;
						atfRemote.setArguments(arguments);
						
						atfRemote.remoteExecute();
						endTime= Calendar.getInstance();
						ATFUtils.addAudit(new Audit(getUsername(),server.getId(),taskName,startTime.getTime(),endTime.getTime(),"Deployment"));
						
					}else{
						System.out.println("Local Execution is enabled.. ");
						atflocal= new AtfLocal();
						String cmd="";
						if(deployScript != null && !deployScript.getpValue().equalsIgnoreCase("")){
							cmd+=deployScript.getpValue();

						}else if(scriptPath != null && !scriptPath.getpValue().equalsIgnoreCase("")){
							cmd+=scriptPath.getpValue()+"/deploy/Deploy.sh";
								
						}else{
							cmd+="Deploy.sh";
						}
						System.out.println("Command to execute: "+cmd);
						if(scriptSudo != null){
							cmd=scriptSudo.getpValue()+" "+cmd;
						}
						
						
						atflocal.setOutputBuffer(output);
						atflocal.setErrorBuffer(error);
						atflocal.setCommand(cmd);
						String arguments=ATFUtils.getDeployParameters(options);	
						arguments+=" "+appName;
						atflocal.setArguments(arguments);		
						atflocal.localExecute();
						endTime= Calendar.getInstance();
						ATFUtils.addAudit(new Audit(getUsername(),server.getId(),taskName,startTime.getTime(),endTime.getTime(),"Deployment"));
					}	
					
					
					clearDescription();
					description=description.append("Deployment Completed");
					running = false;
					if(options.containsKey("emailTo")){
						if(!options.get("emailTo").equalsIgnoreCase("")){
							String subject="Deployment For Application "+appName +" Completed";
							String message= "ServerName: "+server.getServername()+"\n"
											+"Profile:  "+profileManager.getProfileDetails().getProfileName()+"\n"
											+"Start Time: "+startTime.getTime()+"\n"
											+"End Time: "+endTime.getTime()+"\n"
											+"User: "+getUsername()+"\n"
											+"Options:"+options;
							ATFUtils.sendTextEmail(options.get("emailTo"), "", subject, message);
						}
					}
					return "OK";
				}
				
				
			});
			executor.execute(futureTask);
		}else{
			error.append("Already a Task Running");
		}
	}
	public void clearOutput(){
		output= new StringBuffer();	
	}
	public void clearError(){
		error = new StringBuffer();
		
	}
	
	public void clearDescription(){
		description= new StringBuffer();
	}

	

}
